
import os

import wx
import shutil

import ab_ids as ai

import ab_images
import ab_exceptions
import ab_plugins
import ab_statusbar


class _DropTargetFile(wx.FileDropTarget):
    def __init__(self, parent, app):
        wx.FileDropTarget.__init__(self)
        self.app = app
        self.parent = parent

    def OnDropFiles(self, x, y, filenames):
        for filename in filenames:
            self.app.openDocument('viewer', filename)


class CoreMdiFrame(wx.MDIParentFrame):
    def __init__(self, app):
        self.app = app

        self.app.info('Active anaCoreMdiParentFrame')
        top = self.app.readKey(ai.CfgParaAnaFileTop)
        left = self.app.readKey(ai.CfgParaAnaFileLeft)
        width = self.app.readKey(ai.CfgParaAnaFileWidth)
        height = self.app.readKey(ai.CfgParaAnaFileHeight)

        wx.MDIParentFrame.__init__(self, None, -1, "Analyzer for Files",
                                   pos=(top, left), size=(width, height))

        self.plx = self.app.readKey(ai.CfgParaPlxObject)
        self.res = self.app.readKey(ai.CfgParaResourceObject)

        self.index = 0
        # application icon
        img = ab_images.app_icon.GetImage()
        icon = wx.IconFromBitmap(img.ConvertToBitmap())
        self.SetIcon(icon)

        self.tryWrapper = ab_exceptions.TryWrapperFactory(self, self.app)
        self.idmgmt = ai.Ids(self.app, self, self.tryWrapper)

        # add the event
        self.Bind(wx.EVT_CLOSE, self.tryWrapper(self.OnExit))

        # add Main Menu
        self.buildMenubar(self.tryWrapper)

        if self.app.readKey(ai.CfgParaPlatform).hasStatusBar():
            self.statusbar = ab_statusbar.StatusBar(self.app, self)
        else:
            self.statusbar = None

        # set the drop target
        dt = _DropTargetFile(self, self.app)
        self.SetDropTarget(dt)

    def buildMenubar(self, tryWrapper):
        self.mainmenu = wx.MenuBar()

        # make a File menu
        menu = wx.Menu()
        menu.Append(wx.ID_NEW, '&New Content\tCtrl-N',
                    'Create new contents with a dialog')
        menu.AppendSeparator()
        menu.Append(wx.ID_OPEN, '&Open File\tCtrl-O',
                    'Open a file for analyzing')
        menu.Append(ai.id_OpenWithPlx, 'Open &with Plug-ins',
                    'Open a file with the selected plug-in configurations')
        menu.Append(wx.ID_SAVE, '&Save...\tCtrl-S',
                    'Save the opened content with specified formats')
        menu.Append(wx.ID_SAVEAS, 'Save &As...',
                    'Save the opened content...')

        self.buildPlxToolMenu(menu, tryWrapper)

        menu.AppendSeparator()
        menu.Append(wx.ID_CLOSE, '&Close\tCtrl-C',
                    'Close current opened file')
        menu.Append(wx.ID_CLOSE_ALL, 'C&lose All',
                    'Close all opened files')
        menu.AppendSeparator()
        menu.Append(ai.id_DumpContent, '&Dump Content...\tCtrl-D',
                    'Dump snippets of current file')
        menu.AppendSeparator()

        self.recentmenu = wx.Menu()
        self.recent_menu_id = list()
        menu.AppendMenu(wx.ID_FILE, "&Recent Files", self.recentmenu)
        menu.AppendSeparator()
        menu.Append(wx.ID_EXIT, 'E&xit\tCtrl-Q', 'Exit the application')
        self.mainmenu.Append(menu, '&File')

        # make an Edit menu
        menu = wx.Menu()
        menu.Append(wx.ID_FIND, '&Find ...\tCtrl-F',
                    'Find the strign in the active window')
        menu.Append(ai.id_FindPrev, 'Find &Previous\tF3',
                    'Find the previous string')
        menu.Append(ai.id_FindNext, 'Find &Next\tF4',
                    'Find the next string')
        menu.AppendSeparator()
        menu.Append(ai.id_Goto, '&Goto Position...\tCtrl-G',
                    'Go to a specified position')
        menu.AppendSeparator()
        menu.Append(wx.ID_COPY, '&Copy Selected...\tCtrl-C',
                    'Copy the selected contents')
        menu.AppendSeparator()
        menu.Append(ai.id_AsciiTable, 'Show &Ascii Table',
                    'Show an ASCII table')
        menu.AppendSeparator()
        menu.Append(wx.ID_PREFERENCES, 'Pre&ferences',
                    'Set the application preferences')
        self.mainmenu.Append(menu, '&Edit')

        # make a Plug-in menu
        menu = wx.Menu()
        menu.Append(ai.id_InstallPlx, '&Install...',
                    'Install a new plug-in to the application')
        menu.Append(ai.id_RunPlx, '&Run...',
                    'Run a plug-in in the environment')
        menu.AppendSeparator()
        menu.Append(ai.id_PlxInfo, '&Show Plug-in List',
                    'Show all plug-in info')
        self.mainmenu.Append(menu, '&Plug-in')

        # make a Developer menu
        if self.app.readKey(ai.CfgParaDeveloperMethod):
            menu = wx.Menu()
            if wx.VERSION[:2] > (2, 8):
                menu.Append(ai.id_ShowConfig, '&Show config items',
                            'Show the configurable items')
                menu.AppendSeparator()
                menu.Append(ai.id_ShowEnv, '&Show Environment variables',
                            'Show the run-time enviornment')
                menu.AppendSeparator()

            menu.Append(ai.id_OpenAsJson, 'Open &Json tree file',
                        'Open a json file like the one with the atr extension')
            menu.Append(ai.id_ExportJson, '&Export tree in Json',
                        'Export the tree in json instead of atr')
            self.mainmenu.Append(menu, '&Developer')

        # make a Help menu
        menu = wx.Menu()
        menu.Append(wx.ID_HELP_CONTENTS, 'Content\tF1',
                    'Show the help content')
        menu.Append(wx.ID_HELP_INDEX, 'Index...',
                    'Show the help topics')

        menu.AppendSeparator()
        menu.Append(wx.ID_ABOUT, 'About Analyzer for Files...',
                    'About the application')
        self.mainmenu.Append(menu, '&Help')

        # bind the global messages
        for key in xrange(wx.ID_FILE1, wx.ID_FILE9 + 1):
            wx.EVT_MENU(self, key, tryWrapper(self.OnCmd_OpenRecentFile))

        wx.EVT_MENU(self, wx.ID_NEW, tryWrapper(self.OnCmd_New))
        wx.EVT_MENU(self, wx.ID_OPEN, tryWrapper(self.OnCmd_Open))
        wx.EVT_MENU(self, ai.id_OpenWithPlx,
                    tryWrapper(self.OnCmd_OpenWithPlx))
        wx.EVT_MENU(self, wx.ID_CLOSE, tryWrapper(self.OnCmd_Close))
        wx.EVT_UPDATE_UI(self, wx.ID_CLOSE, tryWrapper(self.OnUpdate_Close))
        wx.EVT_MENU(self, wx.ID_CLOSE_ALL, tryWrapper(self.OnCmd_CloseAll))
        wx.EVT_UPDATE_UI(self, wx.ID_CLOSE_ALL,
                         tryWrapper(self.OnUpdate_CloseAll))
        wx.EVT_UPDATE_UI(self, wx.ID_FILE,
                         tryWrapper(self.OnUpdate_RecentFiles))
        wx.EVT_MENU(self, wx.ID_EXIT, tryWrapper(self.OnCmd_Exit))
        wx.EVT_MENU(self, ai.id_AsciiTable,
                    tryWrapper(self.OnCmd_ShowAsciiTable))
        wx.EVT_MENU(self, wx.ID_PREFERENCES,
                    tryWrapper(self.OnCmd_Preferences))
        wx.EVT_MENU(self, ai.id_ShowConfig,
                    tryWrapper(self.OnCmd_ShowConfig))
        wx.EVT_MENU(self, ai.id_ShowEnv, tryWrapper(self.OnCmd_ShowEnv))
        wx.EVT_MENU(self, ai.id_InstallPlx,
                    tryWrapper(self.OnCmd_InstallOrRunPlx))
        wx.EVT_MENU(self, ai.id_RunPlx,
                    tryWrapper(self.OnCmd_InstallOrRunPlx))
        wx.EVT_MENU(self, ai.id_PlxInfo,
                    tryWrapper(self.OnCmd_ShowPlxInfo))
        wx.EVT_MENU(self, ai.id_OpenAsJson,
                    tryWrapper(self.OnCmd_OpenAsJson))
        wx.EVT_MENU(self, wx.ID_HELP_CONTENTS,
                    tryWrapper(self.OnCmd_HelpContents))
        wx.EVT_MENU(self, wx.ID_HELP_INDEX, tryWrapper(self.OnCmd_HelpIndex))
        wx.EVT_MENU(self, wx.ID_ABOUT, tryWrapper(self.OnCmd_About))
        wx.EVT_UPDATE_UI(self, wx.ID_HELP_CONTENTS,
                         tryWrapper(self.OnUpdate_HelpContents))
        wx.EVT_UPDATE_UI(self, wx.ID_HELP_INDEX,
                         tryWrapper(self.OnUpdate_HelpContents))

        self.updateRecentMenu()
        self.SetMenuBar(self.mainmenu)

    def buildPlxToolMenu(self, menu, tryWrapper):
        idmgr = self.getIdsManager()

        # generators
        gen_list = self.plx.getPlxList(ab_plugins.PlxTpGenerator)
        gen_list = self.plx.getFilteredPlxList(gen_list, ab_plugins.PlxCtxTree)
        if len(gen_list) > 0:
            submenu = wx.Menu()
            for plx_name in gen_list:
                submenu.Append(idmgr.getExportedIdWithPlx(plx_name), plx_name)

            menu.AppendSeparator()
            menu.AppendMenu(-1, 'Exported With', submenu,
                            'Export the content with the plugin')

        exports = self.plx.getCreators()
        if len(exports) > 0:
            submenu = wx.Menu()
            for name, export_list in exports:
                if len(export_list) == 1:
                    submenu.Append(
                        idmgr.getCreatorIdWithPlx(name, export_list[0]),
                        '%s:%s' % (self.plx.getElement(name).getShortname(),
                                   export_list[0]))
                elif len(export_list) > 0:
                    export_menu = wx.Menu()
                    for e in export_list:
                        export_menu.Append(idmgr.getCreatorIdWithPlx(
                                           name, e), e)

                    submenu.AppendMenu(idmgr.getCreatorIdWithPlx(name),
                                       name, export_menu)

            menu.AppendSeparator()
            menu.AppendMenu(-1, 'Created With', submenu,
                            'Create new files with the plugin and contents')

    def updateRecentMenu(self):
        recent_files = self.app.getRecentFiles()

        # remove old items
        for index in self.recent_menu_id:
            self.recentmenu.Delete(index)

        self.recent_menu_id = list()
        # recreate the new menu
        for index, filename in enumerate(recent_files):
            menu_id = wx.ID_FILE1 + index
            self.recent_menu_id.append(menu_id)
            self.recentmenu.Append(menu_id, '%d: %s' % (index + 1, filename))

    def updateStatus(self, column, value):
        if self.statusbar is None:
            frame = self.GetActiveChild()
            if hasattr(frame, 'updateStatus'):
                frame.updateStatus(value, column)
        else:
            self.statusbar.update(value, column)

    def getIdsManager(self):
        return self.idmgmt

    def clearStatus(self):
        if self.statusbar is not None:
            self.statusbar.cleanup()

    def cleanup(self):
        top, left = self.GetPosition()
        width, height = self.GetSize()

        self.app.writeKey(ai.CfgParaAnaFileTop, top)
        self.app.writeKey(ai.CfgParaAnaFileLeft, left)
        self.app.writeKey(ai.CfgParaAnaFileWidth, width)
        self.app.writeKey(ai.CfgParaAnaFileHeight, height)

        self.app.closeDocument()

    def checkReboot(self):
        if self.app.readKey(ai.CfgParaAppRestartInd):
            self.app.writeKey(ai.CfgParaAppRestartInd, False)

            dialog = wx.MessageDialog(self,
                                      'The application needs a reboot, '
                                      'restart?', 'Question',
                                      wx.YES_NO | wx.NO_DEFAULT |
                                      wx.ICON_QUESTION)
            if dialog.ShowModal() == wx.ID_YES:
                self.app.writeKey(ai.CfgParaAppRestart, True)
                self.Close()

    def OnExit(self, event):
        self.cleanup()
        self.Destroy()

    def OnCmd_New(self, event):
        rc, title, content, plx, opaque = self.app.getInputWithPlx(self)

        if rc:
            # use 'plx_cnt_viewer' to open
            self.app.openDocument('plx_cnt_viewer', title,
                                  content, plx, _options=opaque)

    def OnCmd_Open(self, event):
        dialog = wx.FileDialog(self, message="Choose files",
                               defaultDir=os.getcwd(),
                               wildcard=self.plx.getExtension(),
                               style=wx.OPEN | wx.MULTIPLE | wx.CHANGE_DIR)

        # use 'viewer' to open the selected files
        if dialog.ShowModal() == wx.ID_OK:
            paths = dialog.GetPaths()
            for filename in paths:
                self.app.openDocument('viewer', filename)

    def OnCmd_OpenWithPlx(self, event):
        rc, filename, plx, opaque = self.app.getOpenWithPlx(self)

        if rc:
            self.app.openDocument('plx_viewer', filename,
                                  filename, plx, _options=opaque)

    def OnCmd_OpenWithSegment(self, event):
        return self.OnCmd_Dispatch('Cmd_OpenWithSegment')

    def OnUpdate_OpenWithSegment(self, event):
        event.Enable(self.OnUpdate_Dispatch('Update_OpenWithSegment'))

    def OnCmd_OpenAsJson(self, event):
        dialog = wx.FileDialog(self, message="Choose files",
                               defaultDir=os.getcwd(),
                               wildcard='Json Files (*.json)|*.json',
                               style=wx.OPEN | wx.MULTIPLE | wx.CHANGE_DIR)

        # use 'viewer' to open the selected files
        if dialog.ShowModal() == wx.ID_OK:
            paths = dialog.GetPaths()
            for filename in paths:
                self.app.openDocument('viewer', filename, json=True)

    def OnCmd_Close(self, event):
        win = self.GetActiveChild()
        if win is not None:
            self.app.closeDocument(win.getTitle(), trigger=True)

    def OnUpdate_Close(self, event):
        event.Enable(self.GetActiveChild() is not None)

    def OnCmd_CloseAll(self, event):
        self.app.closeDocument(trigger=True)

    def OnUpdate_CloseAll(self, event):
        event.Enable(self.GetActiveChild() is not None)

    def OnUpdate_RecentFiles(self, event):
        recent_files = self.app.getRecentFiles()
        event.Enable(len(recent_files) > 0)

    def OnCmd_OpenRecentFile(self, event):
        filename = self.MenuBar.GetLabel(event.GetId())
        # the label format is 'Idx: filename', idx=1..5
        self.app.openDocument('viewer', filename[3:])

    def OnCmd_Exit(self, event):
        self.Close(True)

    def OnCmd_ShowAsciiTable(self, event):
        # use 'ascii' to open the file
        self.app.openDocument('ascii')

    def OnCmd_Preferences(self, event):
        self.app.setPreferences(self)
        self.checkReboot()

    def OnCmd_ShowConfig(self, event):
        self.app.openDocument('cfglist')

    def OnCmd_ShowEnv(self, event):
        self.app.openDocument('envviewer')

    def OnCmd_InstallOrRunPlx(self, event):
        action = 'run'
        if event.GetId() == ai.id_InstallPlx:
            action = 'install'

        dialog = wx.FileDialog(self, message="Choose a Python file",
                               defaultDir=os.getcwd(),
                               wildcard='Python Files (*.py, *.pyc, *.pyo)'
                               '|*.py;*.pyc;*.pyo',
                               style=wx.OPEN | wx.MULTIPLE)

        if dialog.ShowModal() != wx.ID_OK:
            return

        ci = self.plx.getCategory()
        filenames = dialog.GetPaths()
        for name in filenames:
            ret, plxs = self.plx.installFile(name, tryrun=True)
            if not ret:
                wx.MessageBox("'%s' is an invalid plug-in" % name,
                              'Error', wx.OK | wx.CENTRE | wx.ICON_ERROR)
                continue

            if action == 'install':
                dirp = os.path.join(self.app.readKey(ai.CfgParaPlxPath),
                                    ci.getPathWithId(
                                    ab_plugins.PlxTpInstalled))
                new_file = os.path.join(dirp, os.path.basename(name))

                res = True
                if os.path.exists(new_file):
                    dialog = wx.MessageDialog(self,
                                              'The file is existent, '
                                              'replace it?', 'Question',
                                              wx.YES_NO | wx.NO_DEFAULT |
                                              wx.ICON_QUESTION)
                    res = dialog.ShowModal() == wx.ID_YES
                    if res:
                        os.unlink(new_file)

                if res:
                    try:
                        if not os.path.exists(dirp):
                            os.makedirs(dirp)

                        shutil.copy(name, new_file)
                        name = new_file
                    except IOError:
                        wx.MessageBox("Can't %s file %s" % (action, name),
                                      'Error',
                                      wx.OK | wx.CENTRE | wx.ICON_ERROR)
                        continue
                else:
                    continue

            ret, plx_names = self.plx.installFile(name)
            if ret:
                self.app.info("%s '%s'" % (action, name))
                self.app.info("  Instances: %s" % ','.join(plx_names))

    def OnCmd_ShowPlxInfo(self, event):
        # use 'plxlist' to open the file
        self.app.openDocument('plxlist')

    def OnCmd_CreateWith(self, event):
        return self.OnCmd_DispatchWithArgue('Cmd_CreateWith', event)

    def OnUpdate_GenerateWith(self, event):
        event.Enable(self.OnUpdate_DispatchWithArgue(
                     'Update_GenerateWith', event))

    def OnUpdate_HelpContents(self, event):
        hlp = self.app.readKey(ai.CfgParaHelpObject)
        event.Enable(hlp is not None and hlp.isEnable())

    def OnCmd_HelpContents(self, event):
        hlp = self.app.readKey(ai.CfgParaHelpObject)
        if hlp:
            hlp.showHelpContents()

    def OnCmd_HelpIndex(self, event):
        hlp = self.app.readKey(ai.CfgParaHelpObject)
        if hlp:
            hlp.showHelpIndex()

    def OnCmd_About(self, event):
        self.app.showAbout(self)

    def OnCmd_PlxHelpContent(self, event):
        return self.OnCmd_Dispatch('Cmd_PlxHelpContent')

    def OnCmd_SaveWithSegment(self, event):
        return self.OnCmd_Dispatch('Cmd_SaveWithSegment')

    def OnUpdate_SaveWithSegment(self, event):
        event.Enable(self.OnUpdate_Dispatch('Update_SaveWithSegment'))

    def OnCmd_Save(self, event):
        return self.OnCmd_Dispatch('Cmd_Save')

    def OnUpdate_Save(self, event):
        active = self.GetActiveChild() is not None
        event.Enable(active and self.OnUpdate_Dispatch('Update_Save'))

    def OnCmd_Saveas(self, event):
        return self.OnCmd_Dispatch('Cmd_Saveas')

    def OnUpdate_Saveas(self, event):
        event.Enable(self.OnUpdate_Dispatch('Update_Saveas'))

    def OnUpdate_SaveNode(self, event):
        event.Enable(self.OnUpdate_Dispatch('Update_SaveNode'))

    def OnCmd_SaveBinary(self, event):
        return self.OnCmd_Dispatch('Cmd_SaveBinary')

    def OnCmd_SaveHex(self, event):
        return self.OnCmd_Dispatch('Cmd_SaveHex')

    def OnCmd_SaveNode_Binary(self, event):
        return self.OnCmd_Dispatch('Cmd_SaveNode_Binary')

    def OnCmd_SaveNode_Hex(self, event):
        return self.OnCmd_Dispatch('Cmd_SaveNode_Hex')

    def OnCmd_DumpContent(self, event):
        return self.OnCmd_Dispatch('Cmd_DumpContent')

    def OnUpdate_DumpContent(self, event):
        event.Enable(self.OnUpdate_Dispatch('Update_DumpContent'))

    def OnCmd_Find(self, event):
        return self.OnCmd_Dispatch('Cmd_Find')

    def OnUpdate_Find(self, event):
        event.Enable(self.OnUpdate_Dispatch('Update_Find'))

    def OnCmd_FindPrevious(self, event):
        return self.OnCmd_Dispatch('Cmd_FindPrevious')

    def OnUpdate_FindPrevious(self, event):
        event.Enable(self.OnUpdate_Dispatch('Update_FindPrevious'))

    def OnCmd_FindNext(self, event):
        return self.OnCmd_Dispatch('Cmd_FindNext')

    def OnUpdate_FindNext(self, event):
        event.Enable(self.OnUpdate_Dispatch('Update_FindNext'))

    def OnCmd_Goto(self, event):
        return self.OnCmd_Dispatch('Cmd_Goto')

    def OnUpdate_Goto(self, event):
        event.Enable(self.OnUpdate_Dispatch('Update_Goto'))

    def OnCmd_Copy(self, event):
        return self.OnCmd_Dispatch('Cmd_Copy')

    def OnUpdate_Copy(self, event):
        event.Enable(self.OnUpdate_Dispatch('Update_Copy'))

    def OnCmd_CopyItem(self, event):
        return self.OnCmd_DispatchWithArgue('Cmd_CopyItem', event)

    def OnUpdate_CopyItem(self, event):
        event.Enable(self.OnUpdate_DispatchWithArgue('Update_CopyItem', event))

    def OnCmd_ExportWith(self, event):
        return self.OnCmd_DispatchWithArgue('Cmd_ExportWith', event)

    def OnUpdate_ExportWith(self, event):
        event.Enable(self.OnUpdate_Dispatch('Update_ExportWith'))

    def OnCmd_Expand(self, event):
        return self.OnCmd_Dispatch('Cmd_Expand')

    def OnUpdate_Expand(self, event):
        event.Enable(self.OnUpdate_Dispatch('Update_Expand'))

    def OnCmd_ExpandAll(self, event):
        return self.OnCmd_Dispatch('Cmd_ExpandAll')

    def OnUpdate_ExpandAll(self, event):
        event.Enable(self.OnUpdate_Dispatch('Update_ExpandAll'))

    def OnCmd_ExpandChildren(self, event):
        return self.OnCmd_Dispatch('Cmd_ExpandChildren')

    def OnUpdate_ExpandChildren(self, event):
        event.Enable(self.OnUpdate_Dispatch('Update_ExpandChildren'))

    def OnCmd_Collapse(self, event):
        return self.OnCmd_Dispatch('Cmd_Collapse')

    def OnUpdate_Collapse(self, event):
        event.Enable(self.OnUpdate_Dispatch('Update_Collapse'))

    def OnCmd_CollapseAll(self, event):
        return self.OnCmd_Dispatch('Cmd_CollapseAll')

    def OnUpdate_CollapseAll(self, event):
        event.Enable(self.OnUpdate_Dispatch('Update_CollapseAll'))

    def OnCmd_ExportTree(self, event):
        return self.OnCmd_Dispatch('Cmd_ExportTree')

    def OnUpdate_ExportTree(self, event):
        event.Enable(self.OnUpdate_Dispatch('Update_ExportTree'))

    def OnCmd_ExportNode(self, event):
        return self.OnCmd_Dispatch('Cmd_ExportNode')

    def OnUpdate_ExportNode(self, event):
        event.Enable(self.OnUpdate_Dispatch('Update_ExportNode'))

    def OnCmd_ExportWithLevel(self, event):
        return self.OnCmd_Dispatch('Cmd_ExportWithLevel')

    def OnUpdate_ExportWithLevel(self, event):
        event.Enable(self.OnUpdate_Dispatch('Update_ExportWithLevel'))

    def OnCmd_ExportWithJson(self, event):
        return self.OnCmd_Dispatch('Cmd_ExportWithJson')

    def OnUpdate_ExportWithJson(self, event):
        event.Enable(self.OnUpdate_Dispatch('Update_ExportWithJson'))

    def OnCmd_ParseWith(self, event):
        return self.OnCmd_DispatchWithArgue('Cmd_ParseWith', event)

    def OnUpdate_ParseWith(self, event):
        event.Enable(self.OnUpdate_Dispatch('Update_ParseWith'))

    def OnCmd_Dispatch(self, function_name):
        handler = self.GetActiveChild()
        if handler is not None:
            if hasattr(handler, function_name):
                return getattr(handler, function_name)()
            else:
                self.app.debug('%r has not implement function %s' %
                               (handler, function_name))
        else:
            self.app.info('no handler for function %s' % function_name)

        return None

    def OnCmd_DispatchWithArgue(self, function_name, *args, **kws):
        handler = self.GetActiveChild()
        if handler is not None:
            if hasattr(handler, function_name):
                return getattr(handler, function_name)(*args, **kws)
            else:
                self.app.debug('%r has not implement function %s' %
                               (handler, function_name))
        else:
            self.app.info('no handler for function %s' % function_name)

        return None

    def OnUpdate_Dispatch(self, function_name):
        handler = self.GetActiveChild()
        if handler is not None:
            if hasattr(handler, function_name):
                return getattr(handler, function_name)()
        else:
            self.app.debug('no handler for function %s' % function_name)

        return False

    def OnUpdate_DispatchWithArgue(self, function_name, *args, **kws):
        handler = self.GetActiveChild()
        if handler is not None:
            if hasattr(handler, function_name):
                return getattr(handler, function_name)(*args, **kws)
            else:
                self.app.debug('%r has not implement function %s' %
                               (handler, function_name))
        else:
            self.app.info('no handler for function %s' % function_name)

        return False
